﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel.Channels;
using WcfContrib.Extensions.Context;
using WcfContrib.Extensions.Inspectors;
using WcfContrib.Internal;

namespace WcfContrib.Extensions.OutputControllers
{
    static class OutputControllerManager
    {
        internal static object HandleMessage(Message message, bool isReply, ActivationContextExtension context, object correlationState)
        {
            IEnumerable<IOutputInspector> inspectors = GetOutputInspectors(message, isReply, context);

            if (inspectors != null && inspectors.Count() > 0)
            {
                List<object> correlationStates = (correlationState == null)
                    ? correlationStates = new List<object>()
                    : (List<object>)correlationState;

                int stateIndex = 0;
                foreach (var inspector in inspectors)
                {
                    //currently silent catch, might worth doing something here
                    try
                    {
                        Dictionary<OutputArgument, object> outputState;
                        bool processMessage;

                        string output = string.Empty;
                        if (isReply)
                        {
                            object inspectorState = correlationStates[stateIndex++];
                            output = inspector.BuildReplyMessageOutput(message, inspectorState, out processMessage, out outputState);
                        }
                        else
                        {
                            object inspectorState;
                            output = inspector.BuildRequestMessageOutput(message, out inspectorState, out processMessage, out outputState);
                            correlationStates.Add(inspectorState);
                        }

                        if (processMessage && !string.IsNullOrEmpty(output))
                        {
                            IEnumerable<IOutputController> controllers = GetOutputControllers(inspector, message, isReply, context);
                            foreach (var controller in controllers)
                            {
                                //currently silent catch, might worth doing something here
                                try
                                {
                                    controller.OutputMessage(output, outputState);
                                }
                                catch { }
                            }
                        }
                    }
                    catch { }
                }

                return correlationStates;
            }

            return null;
        }

        static IEnumerable<IOutputInspector> GetOutputInspectors(Message message, bool isReply, ActivationContextExtension context)
        {
            return ServiceExtensionsSelectorAttribute.GetInspectors(context.ServiceNamespace, context.ServiceName);
        }

        static IEnumerable<IOutputController> GetOutputControllers(IOutputInspector inspector, Message message, bool isReply, ActivationContextExtension context)
        {
            //currently hard coded, better to create some sort of factory and configuration basis.
            return GetGlobalOutputControllers(context).Union(inspector.Controllers,
                ComparerByType<IOutputController>.Instance);
        }

        static IEnumerable<IOutputController> GetGlobalOutputControllers(ActivationContextExtension context)
        {
            return ServiceExtensionsSelectorAttribute.GetControllers(context.ServiceNamespace, context.ServiceName);
        }
    }
}
